# coding:utf-8
import sys
from typing import Union

from PySide6.QtCore import Qt, QSize, QRect
from PySide6.QtGui import QPainter, QColor, QIcon
from PySide6.QtWidgets import QWidget, QHBoxLayout, QStackedWidget, QApplication
from qfluentwidgets import isDarkTheme, NavigationInterface, qrouter, NavigationItemPosition, \
    FluentIconBase, NavigationTreeWidget, FluentTitleBar, FluentStyleSheet
from qfluentwidgets.common.animation import BackgroundAnimationWidget
from qfluentwidgets.components.widgets.frameless_window import FramelessWindow
from qfluentwidgets.window.stacked_widget import StackedWidget
from qframelesswindow import TitleBarBase


class FluentWindowBase(BackgroundAnimationWidget, FramelessWindow):
    """ Fluent window base class """

    def __init__(self, parent=None):
        self._isMicaEnabled = False
        self._lightBackgroundColor = QColor(240, 244, 249)
        self._darkBackgroundColor = QColor(32, 32, 32)
        super().__init__(parent)
        self.setTitleBar(FluentTitleBar(self))
        self.totalStackedWidget = QStackedWidget(self)

        # show system title bar buttons on macOS
        if sys.platform == "darwin":
            self.setSystemTitleBarButtonVisible(False)

        self.totalStackedWidget.move(0, 0)
        self.totalStackedWidget.resize(self.size())
        self.titleBar.raise_()

    def setCustomBackgroundColor(self, light, dark):
        """ set custom background color

        Parameters
        ----------
        light, dark: QColor | Qt.GlobalColor | str
            background color in light/dark theme mode
        """
        self._lightBackgroundColor = QColor(light)
        self._darkBackgroundColor = QColor(dark)
        self._updateBackgroundColor()

    def _normalBackgroundColor(self):
        return self._darkBackgroundColor if isDarkTheme() else self._lightBackgroundColor

    def paintEvent(self, e):
        super().paintEvent(e)
        painter = QPainter(self)
        painter.setPen(Qt.PenStyle.NoPen)
        painter.setBrush(self.backgroundColor)
        painter.drawRect(self.rect())

    def systemTitleBarRect(self, size: QSize) -> QRect:
        """ Returns the system title bar rect, only works for macOS

        Parameters
        ----------
        size: QSize
            original system title bar rect
        """
        return QRect(size.width() - 75, 0 if self.isFullScreen() else 9, 75, size.height())

    def setTitleBar(self, titleBar):
        super().setTitleBar(titleBar)

        # hide title bar buttons on macOS
        if sys.platform == "darwin" and self.isSystemButtonVisible() and isinstance(titleBar, TitleBarBase):
            titleBar.minBtn.hide()
            titleBar.maxBtn.hide()
            titleBar.closeBtn.hide()

    def resizeEvent(self, e):
        self.titleBar.move(46, 0)
        self.titleBar.resize(self.width() - 46, self.titleBar.height())
        self.totalStackedWidget.resize(self.size())

    def addTotalWidget(self, widget: QWidget):
        widget.setParent(self.totalStackedWidget)
        self.totalStackedWidget.addWidget(widget)

    def setTotalCurrentWidget(self, widget: QWidget):
        self.totalStackedWidget.setCurrentWidget(widget)

    def setTotalCurrentIndex(self, index: int):
        self.totalStackedWidget.setCurrentIndex(index)

    def removeTotalWidget(self, widget: QWidget):
        self.totalStackedWidget.removeWidget(widget)
        widget.deleteLater()


class NavigationWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.horizontalLayout = QHBoxLayout(self)
        self.verticalLayout = QHBoxLayout()
        self.navigationInterface = NavigationInterface(self, showReturnButton=True)
        self.stackedWidget = StackedWidget(self)

        self.__initWidget()
        self.__initLayout()

    def __initWidget(self):
        self.navigationInterface.setExpandWidth(150)
        FluentStyleSheet.FLUENT_WINDOW.apply(self.stackedWidget)

    def __initLayout(self):
        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.setContentsMargins(0, 48, 0, 0)
        self.horizontalLayout.setSpacing(0)
        self.horizontalLayout.addWidget(self.navigationInterface, 0, Qt.AlignmentFlag.AlignLeft)
        self.verticalLayout.addWidget(self.stackedWidget, 1)
        self.horizontalLayout.addLayout(self.verticalLayout, 1)

    def addSubInterface(self, interface: QWidget, icon: Union[FluentIconBase, QIcon, str], text: str,
                        position=NavigationItemPosition.TOP, parent=None, isTransparent=False) -> NavigationTreeWidget:
        """ add sub interface, the object name of `interface` should be set already
        before calling this method

        Parameters
        ----------
        interface: QWidget
            the subinterface to be added

        icon: FluentIconBase | QIcon | str
            the icon of navigation item

        text: str
            the text of navigation item

        position: NavigationItemPosition
            the position of navigation item

        parent: QWidget
            the parent of navigation item

        isTransparent: bool
            whether to use transparent background
        """
        if not interface.objectName():
            raise ValueError("The object name of `interface` can't be empty string.")
        if parent and not parent.objectName():
            raise ValueError("The object name of `parent` can't be empty string.")

        interface.setProperty("isStackedTransparent", isTransparent)
        self.stackedWidget.addWidget(interface)

        # add navigation item
        routeKey = interface.objectName()
        item = self.navigationInterface.addItem(
            routeKey=routeKey,
            icon=icon,
            text=text,
            onClick=lambda: self.switchTo(interface),
            position=position,
            tooltip=text,
            parentRouteKey=parent.objectName() if parent else None
        )

        # initialize selected item
        if self.stackedWidget.count() == 1:
            self.stackedWidget.currentChanged.connect(self._onCurrentInterfaceChanged)
            self.navigationInterface.setCurrentItem(routeKey)
            qrouter.setDefaultRouteKey(self.stackedWidget, routeKey)

        self._updateStackedBackground()

        return item

    def removeInterface(self, interface, isDelete=False):
        self.navigationInterface.removeWidget(interface.objectName())
        self.stackedWidget.removeWidget(interface)
        interface.hide()

        if isDelete:
            interface.deleteLater()

    def _updateStackedBackground(self):
        isTransparent = self.stackedWidget.currentWidget().property("isStackedTransparent")
        if bool(self.stackedWidget.property("isTransparent")) == isTransparent:
            return

        self.stackedWidget.setProperty("isTransparent", isTransparent)
        self.stackedWidget.setStyle(QApplication.style())

    def _onCurrentInterfaceChanged(self, index: int):
        widget = self.stackedWidget.widget(index)
        self.navigationInterface.setCurrentItem(widget.objectName())
        qrouter.push(self.stackedWidget, widget.objectName())

        self._updateStackedBackground()

    def switchTo(self, interface: QWidget):
        self.stackedWidget.setCurrentWidget(interface, popOut=False)


class FluentWindow(FluentWindowBase):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.navigationWidget = NavigationWidget(self)

        self.addTotalWidget(self.navigationWidget)
        self.navigationInterface.displayModeChanged.connect(self.titleBar.raise_)
        self.navigationInterface.setCollapsible(False)
        self.navigationInterface.setMenuButtonVisible(False)

    @property
    def navigationInterface(self):
        return self.navigationWidget.navigationInterface

    @property
    def stackedWidget(self):
        return self.navigationWidget.stackedWidget

    def addSubInterface(self, interface: QWidget, icon: Union[FluentIconBase, QIcon, str], text: str,
                        position=NavigationItemPosition.TOP, parent=None, isTransparent=False) -> NavigationTreeWidget:
        return self.navigationWidget.addSubInterface(interface, icon, text, position, parent, isTransparent)


